package com.qingzhu.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.Page;
import com.qingzhu.dao.*;
import com.qingzhu.dao.impl.*;
import com.qingzhu.pojo.*;
import com.qingzhu.pojovo.SearchResult;
import com.qingzhu.service.GoodsService;
import com.qingzhu.util.CreateCustomPage;
import com.qingzhu.util.ListTypeHandler;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class GoodsServiceImpl implements GoodsService {
    GoodsDao goodsDao = new GoodsDaoImpl();
    BrandDao brandDao = new BrandDaoImpl();
    ItemDao itemDao = new ItemDaoImpl();
    SpecificationDao specificationDao = new SpecificationDaoImpl();
    SpecificationOptionDao specificationOptionDao = new SpecificationOptionDaoImpl();
    EditionDao editionDao = new EditionDaoImpl();

    @Override
    public List<Brand> findBrandAll() {
        // 查询所有的品牌
        List<Brand> brands = brandDao.findBrandAll();
        // 查询品牌对应的所有的手机型号
        brands.forEach(brand -> {
            List<Goods> goodsList = goodsDao.findGoodsByBrandId(brand.getId());
            // 查询个品牌默认的SKP
            goodsList.forEach(goods -> {
                Item defaultItem = itemDao.findById(goods.getDefaultItemId(),true);
                goods.setDefaultItem(defaultItem);
            });
            brand.setGoodsList(goodsList);
        });
        return brands;
    }

    @Override
    public List<Specification> findSpecificationAll() {
        List<Specification> specifications = specificationDao.findSpecificationAll();
        List<Specification> copySpecifications = new ArrayList<>();
        specifications.forEach(specification -> {
            List<SpecificationOption> specificationOptions = specificationOptionDao.findBySpecificationId(specification.getId());
            specification.setOptions(specificationOptions);
            copySpecifications.add(specification);
        });
        return copySpecifications;
    }

    @Override
    public Goods findGoodsById(int goodsId) {
        Goods goods = findGoodsFromId(goodsId, true,true);
        return goods;
    }
    /* 参数说明
     * goodsId      商品ID
     * itemSpecs    是否需要查询该商品包含的所有SKU详情列表 */
    @Override
    public Goods findGoodsFromId(int goodsId, boolean itemSpecs, boolean excludeDel) {
        Goods goods = goodsDao.findGoodsById(goodsId,excludeDel);

        if (itemSpecs) {
            // 根据spu查询所有的sku（即该产品对应的所有单品的规格列表）
            List<Item> itemList = itemDao.findByGoodsAll(goods.getId(),excludeDel);
            Set<String> colors = new HashSet<>();
            Set<String> editions = new HashSet<>();
            Set<String> networks = new HashSet<>();
            itemList.forEach(item -> {
                colors.add(item.getColour());
                editions.add(item.getEdition());
                networks.add(item.getNetwork());
            });
            goods.setColours(colors);
            goods.setEditions(editions);
            goods.setNetworks(networks);
        }

        // 获取默认选中的SKU参数
        Item item = itemDao.findById(goods.getDefaultItemId(),excludeDel);
        goods.setDefaultItem(item);

        // 将关联的SPU规格转成Map集合
        Map<String, List<String>> specificationMap = attributeStrToMap(goods);
        // 封装SPU规格参数
        goods.setMap(specificationMap);
        return goods;
    }

    @Override
    public Item findItem(int goodsId, String edition, String colour, String network) {
        Item item = itemDao.findItem(goodsId, edition, colour, network);
        return item;
    }

    @Override
    public Page<Goods> findGoodsByLike(String keyword, int pageNum, int pageSize) {
        Page<Goods> goodsList = findGoodsByLike(keyword, pageNum, pageSize, false,true);
        return goodsList;
    }
    /* 【参数说明】
     * keyword  模糊查询的关键字
     * pageNum  分页起始页
     * pageSize 分页的页面大小
     * attributeStrIsToMap 是否需要将关联的SPU规格转成Map结合储存 */
    @Override
    public Page<Goods> findGoodsByLike(String keyword, int pageNum, int pageSize, boolean attributeStrIsToMap,boolean excludeDel) {
        // 如果查询的是全部商品，就将条件置为null
        if (keyword == null || keyword.equals("全部商品")) {
            keyword = null;
        }
        Page<Goods> goodsList = goodsDao.findGoodsByLike(keyword,pageNum,pageSize,excludeDel);
        // 查询默认的SKU。如果被允许，关联的SPU规格也将从字符串串集转换成Map集合
        goodsList.forEach(goods -> {
            if (attributeStrIsToMap) {
                Map<String, List<String>> attributeMap = attributeStrToMap(goods);
                goods.setMap(attributeMap);
            }
            Item item = itemDao.findById(goods.getDefaultItemId(),excludeDel);
            goods.setDefaultItem(item);
        });
        return goodsList;
    }

    @Override
    public CustomPage<Goods> screenSearch(SearchResult searchResult) {
        // 品牌范围查询
        List<Goods> brandTOGoods = null;
        if (searchResult.getCheckBrandList().size() > 0) {
            brandTOGoods = brandScreen(searchResult.getCheckBrandList());
        }
        // 规格范围查询
        List<Goods> specTOGoods = null;
        if (searchResult.getCheckSpecList().size() > 0) {
            specTOGoods = specScreen(searchResult.getCheckSpecList());
        }
        // 合并查询结果并取交集
        List<Goods> goodsList = new ArrayList<>();
        if (brandTOGoods != null && specTOGoods != null) {
            Map<Goods, Long> map = Stream.of(brandTOGoods.stream(), specTOGoods.stream())
                    .flatMap(g -> g)
                    .collect(Collectors.groupingBy(goods -> goods, Collectors.counting()));
            map.forEach((k,v) -> {
                if (v == 2) {
                    goodsList.add(k);
                }
            });
            // 开始逻辑分页
            CustomPage<Goods> page = createPage(goodsList, searchResult.getPageNum(), searchResult.getPageSize());
            System.out.println("最终的筛选结果预览："+page);
            return page;
        }else if (brandTOGoods != null) {
            // 开始逻辑分页
            CustomPage<Goods> page = createPage(brandTOGoods, searchResult.getPageNum(), searchResult.getPageSize());
            System.out.println("最终的筛选结果预览："+page);
            return page;
        }else if (specTOGoods != null) {
            // 开始逻辑分页
            CustomPage<Goods> page = createPage(specTOGoods, searchResult.getPageNum(), searchResult.getPageSize());
            System.out.println("最终的筛选结果预览："+page);
            return page;
        }
        System.out.println("最终的筛选结果为空！");
        return null;
    }

    @Override
    public List<Item> findItemsFromGoodsId(int goodsId, boolean excludeDel) {
        return itemDao.findByGoodsAll(goodsId,excludeDel);
    }

    @Override
    public Item findItemfromId(int itemId) {
        // 已被设置为下架或删除的产品也需要查询
        Item item = itemDao.findById(itemId,false);
        // 将手机版本转换成内存信息储存
        String editionName = item.getEdition();
        Edition edition = editionDao.findEditionFromName(editionName);
        item.setRunMemoryId(edition.getRunMemoryId());
        item.setFuselageMemoryId(edition.getFuselageMemoryId());
        return item;
    }

    @Override
    public int addGoods(Goods goods, Item item) {
        // 添加商品到数据库，并得到一个自增ID
        goodsDao.addGoods(goods);
        // 把从前台获取到的SKU数据转成需要添加的数据(前台传递的规格参数是以ID的形式存在，需要转成规格名称)
        item = createItem(goods.getId(), item);
        // 将SKU插入到数据库，并返回一个自增ID
        itemDao.addItem(item);
        // 拿到SKU单品的自增ID后，重新给SPU添加默认的SKU单品信息
        goods.setDefaultItemId(item.getId());
        return goodsDao.updateGoods(goods);
    }

    @Override
    public int addItem(int goodsId, Item item) {
        item = createItem(goodsId, item);
        return itemDao.addItem(item);
    }

    @Override
    public int updateItem(Item item) {
        // 获取当前的时间初始化修改时间
        DateTime date = DateUtil.date();
        item.setUpdateTime(date);
        // 将内存信息转换成手机版本信息储存
        int runMemoryId = item.getRunMemoryId();
        int fuselageMemoryId = item.getFuselageMemoryId();
        Edition edition = editionDao.findEditionFromMemory(runMemoryId, fuselageMemoryId);
        item.setEdition(edition.getName());
        return itemDao.updateItem(item);
    }

    @Override
    public int updateGoods(Goods goods) {
        // 将SPU参数取出并转化成数据库储存的字符串格式
        String attributeStr = mapToAttributeStr(goods.getMap());
        goods.setAttributeList(attributeStr);
        // 修改商品信息
        int result = goodsDao.updateGoods(goods);
        return result;
    }

    @Override
    public int updateItemState(String state, String itemId) {
        return itemDao.updateItemState(state,itemId);
    }

    @Override
    public int updateItemDelStateAll(String state, List<String> itemIds) {
        itemIds.forEach(id -> {
            itemDao.updateItemState(state,id);
        });
        return itemIds.size();
    }

    @Override
    public int updateGoodsState(String state, String goodsId) {
        if (state.equals("2")) {
            // 下架所有关联该商品的单品
            itemDao.downItemByGoodsId(state,goodsId);
        }else if (state.equals("1")) {
            // 上架该商品绑定的默认单品
            Goods goods = goodsDao.findGoodsById(Integer.parseInt(goodsId), false);
            itemDao.updateItemState(state,String.valueOf(goods.getDefaultItemId()));
        }
        int result = goodsDao.updateGoodsState(state, goodsId);
        return result;
    }


    /* 将关联的SPU规格转成集合储存
     * 数据结构：{"sim":['SIM卡类型','135']}
     * 说明：以规格别名为key，规格名称和规格默认参数ID为值。规格名称占0号位，参数ID占1号位；如果包含多个规格参数值则依次为3号位和4号位
     * 双摄结构：{"hzsxt":['后置摄像头','1600','后置摄像头','2000']} */
    public Map<String,List<String>> attributeStrToMap(Goods goods) {
        ListTypeHandler<String> typeHandler = new ListTypeHandler<>();

        // 查询SPU规格参数
        Map<String,List<String>> specificationMap = new HashMap();  // SPU规格容器，用来储存产品详细的SPU规格参数
        ArrayList<String> specificationList = new ArrayList();      // 储存SPU规格的名称，用来判断是否为重复查询到的规格
        // 获取商品的SPU规格列表
        String phoneSpecification = goods.getAttributeList();
        // 将字符串类型的SPU规格列表转成集合
        List<String> phoneSpecifications = typeHandler.stringToList(phoneSpecification);
        // 遍历参数集合
        phoneSpecifications.forEach(p -> {
            // 查询规格参数信息
            SpecificationOption specificationOption = specificationOptionDao.findById(Integer.parseInt(p));
            String optionName = specificationOption.getOptionName();
            // 拿到规格信息(规格名称)
            Specification specification = specificationDao.findById(specificationOption.getSpecId());
            String specName = String.valueOf(specification.getSpecAliasName());
            // 如果规格名称已经存在过，做以下处理替换规格信息
            if (specificationList.contains(specName)) {
                List<String> optionNameList = specificationMap.get(specName);
                optionNameList.add(optionName);
                optionNameList.add(p);
                specificationMap.put(specName,optionNameList);
            }else {
                // 如果规格名称第一次出现，直接封装规格信息（规格名称+默认的规格参数）
                ArrayList<String> arrayList = new ArrayList<>();
                arrayList.add(optionName);
                arrayList.add(p);
                specificationMap.put(specName,arrayList);
            }
            // 将规格名称添加到容器
            specificationList.add(specName);
        });
        return specificationMap;
    }
    // 获取商品对象
    public Item createItem(int goodId, Item item) {
        // 添加关联的SPU
        item.setGoodsId(goodId);
        // 根据规格id到数据库中查询SKU规格
        SpecificationOption colorOption = specificationOptionDao.findById(Integer.parseInt(item.getColour()));
        SpecificationOption networkOption = specificationOptionDao.findById(Integer.parseInt(item.getNetwork()));
        // 处理手机版本 如：120/126 => 2GB+16G
        String editionIds = item.getEdition();
        String editionY = editionIds.split("/")[0];
        String editionJ = editionIds.split("/")[1];
        Edition edition = editionDao.findEditionFromMemory(Integer.parseInt(editionY), Integer.parseInt(editionJ));
        // 将查询的结果封装到实体类中
        item.setColour(colorOption.getOptionName());
        item.setNetwork(networkOption.getOptionName());
        item.setEdition(edition.getName());
        return item;
    }
    // 将接收到的集合参数转成关联的SPU字符串
    public String mapToAttributeStr(Map<String, List<String>> map) {
        // 将map中的数据取出
        List<String> list = new ArrayList<>();
        List<String> qzsxtList = map.get("qzsxt");
        list.add(qzsxtList.get(1));
        List<String> hzsxtList = map.get("hzsxt");
        list.add(hzsxtList.get(1));
        List<String> spzlList = map.get("spzl");
        list.add(spzlList.get(1));
        List<String> zpccList = map.get("zpcc");
        list.add(zpccList.get(1));
        List<String> cpuList = map.get("cpu");
        list.add(cpuList.get(1));
        List<String> xtnhList = map.get("xtnh");
        list.add(xtnhList.get(1));
        List<String> simList = map.get("sim");
        list.add(simList.get(1));
        List<String> dcrlList = map.get("dcrl");
        list.add(dcrlList.get(1));
        // 将取出后的数据变成关联的规格集字符串
        ListTypeHandler<String> typeHandler = new ListTypeHandler<>();
        String attributeStr = typeHandler.listToString(list);
        return attributeStr;
    }
    /* 进行品牌的范围筛选搜索 */
    private List<Goods> brandScreen (List<String> checkBrandList) {
        // 找到品牌信息
        String brandName = checkBrandList.get(0).split("：")[1];
        Brand brand = brandDao.findByName(brandName);
        // 根据品牌查找商品
        List<Goods> goodsList = goodsDao.findGoodsByBrandId(brand.getId());
        System.out.println("品牌筛选结果："+goodsList);
        return goodsList;
    }
    /* 进行规格的范围搜索并筛选 */
    private List<Goods> specScreen (List<String> checkSpecList) {
        // 定义数据库中SPU包含的规格范围
        Integer[] goodsSpec = {27,28,30,31,32,35,36,39};
        List<Integer> goodsSpecIdList = Arrays.asList(goodsSpec);
        // 定义数据库中SKU包含的规格范围
        Integer[] itemSpec = {33,34,37,38};
        List<Integer> itemSpecIdList = Arrays.asList(itemSpec);
        // 判断是查询SPU表还是SKU表
        List<Integer> goodsSpecList = new ArrayList<>();    // 储存查询SPU的规格id
        Map<String,String> itemSpecMap = new HashMap<>();   // 储存SKU的查询参数
        checkSpecList.forEach(s -> {
            // 获取规格的名称
            String specName = s.split("：")[0];
            // 根据规格的名称获取到规格信息
            Specification spec = specificationDao.findIdFromName(specName);
            if (goodsSpecIdList.contains(spec.getId())) {
                // 根据规格名称的id和规格参数名称确定规格参数，并获取到规格参数的id
                SpecificationOption option = specificationOptionDao.findIdFromName(s.split("：")[1],spec.getId());
                goodsSpecList.add(option.getId());
            }else if (itemSpecIdList.contains(spec.getId())) {
                itemSpecMap.put(specName,s.split("：")[1]);
            } else {
                System.out.println("查询失败！原因是该规格没有包含在规定的搜索范围之内");
            }
        });
        // 根据SPU规格查询商品信息
        List<Goods> goodsFromAttribute = null;
        if (goodsSpecList.size() > 0) {
            goodsFromAttribute = findGoodsFromAttribute(goodsSpecList);
//            System.out.println("SPU商品集："+goodsFromAttribute);
        }else {
            System.out.println("没有找到SPU规格");
        }
        // 根据SKU规格查询商品信息
        List<Goods> goodsFromItem = null;
        if (itemSpecMap.size() > 0) {
            goodsFromItem = findGoodsFromItem(itemSpecMap);
//            System.out.println("SKU商品集："+goodsFromItem);
        }else {
            System.out.println("没有找到SKU规格");
        }
        // 合并查询结果并取出SPU和SKU查询的结果交集
        List<Goods> goodsList = new ArrayList<>();
        if (goodsFromAttribute != null && goodsFromItem != null) {
            // 合并查询结果并取交集
            Map<Goods, Long> map = Stream.of(goodsFromAttribute.stream(), goodsFromItem.stream())
                    .flatMap(g -> g)
                    .collect(Collectors.groupingBy(goods -> goods, Collectors.counting()));
            map.forEach((k,v) -> {
                if (v == 2) {
                    goodsList.add(k);
                }
            });
            System.out.println("规格筛选结果："+goodsList);
            return goodsList;
        }else if (goodsFromAttribute != null) {
            System.out.println("规格筛选结果："+goodsFromAttribute);
            return goodsFromAttribute;
        }else if (goodsFromItem != null) {
            System.out.println("规格筛选结果："+goodsFromItem);
            return goodsFromItem;
        }
        System.out.println("规格筛选结果为空！");
        return goodsList;
    }
    /* 根据SPU规格查询商品信息 */
    private List<Goods> findGoodsFromAttribute (List<Integer> goodsScreenList) {
        // 根据获取到的SPU规格集查找包含每个规格的商品
        List<List<Goods>> lists = new ArrayList<>();
        goodsScreenList.forEach(g -> {
            List<Goods> goodsList = goodsDao.findGoodsFromAttribute(String.valueOf(g));
            lists.add(goodsList);
            goodsList.forEach(goods -> System.out.println(goods.getGoodsName()));
        });
        // 将所有的查询结果合并并作交集运算
        List<Goods> goodsList = new ArrayList<>();
        Map<Goods, Long> collectMap = lists.stream().flatMap(gl -> gl.stream())
                .collect(Collectors.groupingBy(goods -> goods, Collectors.counting()));
        collectMap.forEach((k,v) -> {
            if (v == goodsScreenList.size()) {
                goodsList.add(k);
            }
        });
        return goodsList;
    }
    /* 根据SKU规格查询商品信息 */
    private List<Goods> findGoodsFromItem (Map<String,String> itemSpecMap) {
        // 找到所有满足条件的商品id
        List<Integer> goodsIds = itemDao.findItemFromSpec(itemSpecMap.get("机身颜色"),
                                                    itemSpecMap.get("网络"),
                                                    itemSpecMap.get("运行内存"),
                                                    itemSpecMap.get("机身内存"));
        // 将所有的查询结果合并并去除重复的商品id，然后根据商品id去查询商品的信息
        List<Goods> goodsList = new ArrayList<>();
        goodsIds.stream().distinct().forEach(g -> {
            goodsList.add(goodsDao.findGoodsById(g,true));
        });
        return goodsList;
    }
    /* 自定义逻辑分页 */
    private CustomPage<Goods> createPage (List<Goods> list, int pageNum, int pageSize) {
        // 查询每个SPU默认选中的SKU
        list.forEach(goods -> {
            Item item = itemDao.findById(goods.getDefaultItemId(),true);
            goods.setDefaultItem(item);
        });
        // 开始分页
        CustomPage<Goods> page = new CreateCustomPage<Goods>().createPage(list, pageNum, pageSize);
        return page;
    }
}